﻿-------------------------------------------------------------------------------
-- Быстрый поиск в редакторе. © SimSU
-------------------------------------------------------------------------------

---- Настройки
local function Settings()
-- Начало файла Profile\SimSU\Editor_QuickSearch.cfg
return{
  Prior=52;
  KeyForward="RAlt"; --PriorForward=50;
  KeyBack="RCtrl"; --PriorBack=50;
  KeyBS="BS"; --PriorBS=50;
  KeyNext="CtrlEnter"; PriorNext=51;
  KeyStop="RAlt RCtrl Esc"; --PriorStop=50;
  KeyNextWord="CtrlAltDown"; --PriorNextWord=50;
  KeyPrevWord="CtrlAltUp"; --PriorPrevWord=50;

  VeryQuick=true; -- Очень быстрый поиск :)
  CaseSensitivity=false; -- Учитывать регистр.
  ThatWord="[%w_]+"; -- Что считается словом.
}
-- Конец файла Profile\SimSU\Editor_QuickSearch.cfg
end

---- Локализация
_G.far.lang=far.lang or win.GetEnv("farlang")
-- Встроенные языки / Buildin laguages
local function Messages()
if far.lang=="Russian" then
-- Начало файла Profile\SimSU\Editor_QuickSearchRussian.lng
return{
  Descr="Быстрый поиск в редакторе. © SimSU";
  DescrForward="Быстрый поиск вперед в редакторе. © SimSU";
  DescrBack="Быстрый поиск назад в редакторе. © SimSU";
  DescrBS="Быстрый поиск в редакторе - корректировка. © SimSU";
  DescrNext="Быстрый поиск в редакторе - следующее совпадение. © SimSU";
  DescrStop="Быстрый поиск в редакторе - прекратить. © SimSU";
  DescrNextWord="Быстрый поиск в редакторе - следующее слово. © SimSU";
  DescrPrevWord="Быстрый поиск в редакторе - предыдущее слово. © SimSU";
}
-- Конец файла Profile\SimSU\Editor_QuickSearchRussian.lng
else--if far.lang=="English" then
-- Begin of file Profile\SimSU\Editor_QuickSearchEnglish.lng
return{
  Descr="Quick search in the editor. © SimSU";
  DescrForward="Быстрый поиск вперед в редакторе. © SimSU";
  DescrBack="Быстрый поиск назад в редакторе. © SimSU";
  DescrBS="Быстрый поиск в редакторе - корректировка. © SimSU";
  DescrNext="Быстрый поиск в редакторе - следующее совпадение. © SimSU";
  DescrStop="Быстрый поиск в редакторе - прекратить. © SimSU";
  DescrNextWord="Быстрый поиск в редакторе - следующее слово. © SimSU";
  DescrPrevWord="Быстрый поиск в редакторе - предыдущее слово. © SimSU";
}
-- End of file Profile\SimSU\Editor_QuickSearchEnglish.lng
end end

local M=(loadfile(win.GetEnv("FARPROFILE").."\\SimSU\\Editor_QuickSearch"..far.lang..".lng") or Messages)()
local S=(loadfile(win.GetEnv("FARLOCALPROFILE").."\\SimSU\\Editor_QuickSearch.cfg") or loadfile(win.GetEnv("FARPROFILE").."\\SimSU\\Editor_QuickSearch.cfg") or Settings)()

local SimSU=SimSU or {}
SimSU.Editor_QuickSearch={}
-------------------------------------------------------------------------------
local QSearch,Direction,StartLine,StartPos

local ThatWord=S.ThatWord or "[%w_]+"
local _ThatWord="^("..ThatWord..")"
local ThatWord_="("..ThatWord..")$"

function SimSU.Editor_QuickSearch.Find(txt,Line,Pos,Dir)
  if txt and txt:len()>0 then
    local Q=S.VeryQuick and 1 or 0
    txt= S.CaseSensitivity and txt or txt:upper()
    Line= Line or Editor.CurLine
    Pos= Pos or Editor.RealPos
    Dir= Dir or Direction or 1
    local Case= S.CaseSensitivity and 1 or 0
    local str=editor.GetString(nil,Line,3)
    local Beg= Dir==1 and mf.index(str:sub(Pos+Q),txt,Case)+1 or mf.rindex(str:sub(1,Pos-Q),txt,Case)+1
    if Beg~=0 then
      Beg= Dir==1 and Beg+Pos-1+Q or Beg
    else
      for i=Line+Dir,Dir==1 and Editor.Lines or 1, Dir do
        str=editor.GetString(nil,i,3)
        Beg= Dir==1 and mf.index(str,txt,Case)+1 or mf.rindex(str,txt,Case)+1
        if Beg~=0 then Line=i; break end
      end
    end
    if Beg~=0 then
      editor.Select(nil,1,Line,Beg,txt:len(),1)
      editor.SetPosition(nil,Line,Beg)
      editor.Redraw()
      return true
    else
      Editor.Sel(4)
      return false
    end
  end
end

function SimSU.Editor_QuickSearch.Go(Rec)
  local Key=far.InputRecordToName(Rec)
  if Key=="\01" then return end -- Глючит far InputRecordToName возвращает  при отпускании модификаторов...
  if Key=="Space" then Key=" " end
  if Key and Key:len()==1 then
    QSearch=QSearch..Key
    Editor.SetTitle((Direction==1 and "↓:" or "↑:")..QSearch)
    Editor.Sel(4)
    SimSU.Editor_QuickSearch.Find(QSearch)
    return 1
  elseif not((Key=="Ctrl" or Key=="RCtrl" or Key=="Alt" or Key=="RAlt" or Key=="Shift")) then
    QSearch=nil; Editor.SetTitle("")
  end
end

function SimSU.Editor_QuickSearch.Stop()
  QSearch=nil
  Editor.SetTitle("")
end

function SimSU.Editor_QuickSearch.Forward()
  QSearch=""
  Direction=1
  Editor.SetTitle("↓:")
  StartLine=Editor.CurLine
  StartPos=Editor.RealPos
end

function SimSU.Editor_QuickSearch.Back()
  QSearch=""
  Direction=-1
  Editor.SetTitle("↑:")
  StartLine=Editor.CurLine
  StartPos=Editor.RealPos
end

function SimSU.Editor_QuickSearch.BS()
  if QSearch:len()>0 then
    QSearch=QSearch:sub(1,-2)
    Editor.SetTitle((Direction==1 and "↓:" or "↑:")..QSearch)
    SimSU.Editor_QuickSearch.Find(QSearch,StartLine,StartPos)
    if QSearch:len()==1 then Editor.Sel(4) end
  else
    SimSU.Editor_QuickSearch.Stop()
    Editor.Sel(4)
  end
end

function SimSU.Editor_QuickSearch.Next()
  SimSU.Editor_QuickSearch.Find(QSearch)
end

function SimSU.Editor_QuickSearch.GetWord(Line,Pos)
  local Line= Line or Editor.CurLine; local Pos= Pos or Editor.RealPos
  local s=editor.GetString(nil,Line,3)
  local b,e = s:cfind(_ThatWord,Pos); Pos= e or Pos-1
  local b,e,w=s:sub(1,Pos):cfind(ThatWord_); return w,b,e
end

function SimSU.Editor_QuickSearch.NextWord()
  SimSU.Editor_QuickSearch.Stop()
  local Word = Editor.SelValue~="" and  Editor.SelValue or SimSU.Editor_QuickSearch.GetWord()
  SimSU.Editor_QuickSearch.Find(Word)
end

function SimSU.Editor_QuickSearch.PrevWord()
  SimSU.Editor_QuickSearch.Stop()
  local Word = Editor.SelValue~="" and  Editor.SelValue or SimSU.Editor_QuickSearch.GetWord()
  SimSU.Editor_QuickSearch.Find(Word,nil,nil,-1)
end
-------------------------------------------------------------------------------
if not Macro then return {Editor_QuickSearch=SimSU.Editor_QuickSearch} end

local ok, mod = pcall(require,"SimSU.Editor_QuickSearch"); if ok then SimSU=mod else _G.SimSU=SimSU end
-------------------------------------------------------------------------------
Event {group="EditorInput"; priority=S.Prior; description=M.Descr;
  condition=function(Rec) return QSearch and Rec.KeyDown end;
  action=SimSU.Editor_QuickSearch.Go;
}

Macro {area="Editor"; key=S.KeyForward; priority=S.PriorForward; description=M.DescrForward;
  condition=function() return not QSearch end;
  action=SimSU.Editor_QuickSearch.Forward;
}
Macro {area="Editor"; key=S.KeyBack; priority=S.PriorBack; description=M.DescrBack;
  condition=function() return not QSearch end;
  action=SimSU.Editor_QuickSearch.Back;
}

Macro {area="Editor"; key=S.KeyBS; priority=S.PriorBS; description=M.DescrBS;
  condition=function() return QSearch end;
  action=SimSU.Editor_QuickSearch.BS;
}

Macro {area="Editor"; key=S.KeyNext; priority=S.PriorNext; description=M.DescrNext;
  condition=function() return QSearch end;
  action=SimSU.Editor_QuickSearch.Next;
}

Macro {area="Editor"; key=S.KeyStop; priority=S.PriorStop; description=M.DescrStop;
  condition=function() return QSearch end;
  action=SimSU.Editor_QuickSearch.Stop;
}

Macro {area="Editor"; key=S.KeyNextWord; priority=S.PriorNextWord; description=M.DescrNextWord;
  action=SimSU.Editor_QuickSearch.NextWord;
}

Macro {area="Editor"; key=S.KeyPrevWord; priority=S.PriorPrevWord; description=M.DescrPrevWord;
  action=SimSU.Editor_QuickSearch.PrevWord;
}
